"""
业务异常类和异常编码定义
提供统一的异常编码管理和业务异常处理
"""
from enum import Enum
from typing import Optional

from fastapi import HTTPException


class ErrorCode(Enum):
    """
    统一的业务异常编码定义
    格式: (HTTP状态码, 业务错误码, 错误描述)
    """

    # 通用错误 (400系列)
    BAD_REQUEST = (400, "BAD_REQUEST", "请求参数错误")
    UNAUTHORIZED = (401, "UNAUTHORIZED", "未授权访问")
    FORBIDDEN = (403, "FORBIDDEN", "禁止访问")
    NOT_FOUND = (404, "NOT_FOUND", "资源不存在")
    CONFLICT = (409, "CONFLICT", "资源冲突")
    GONE = (410, "GONE", "资源已失效")

    # 用户相关错误 (1000-1999)
    USER_NOT_FOUND = (401, "USER_NOT_FOUND", "用户不存在或已被禁用")
    USER_DISABLED = (401, "USER_DISABLED", "用户已被禁用")
    USERNAME_EXISTS = (400, "USERNAME_EXISTS", "用户名已存在")
    EMAIL_EXISTS = (400, "EMAIL_EXISTS", "邮箱已被注册")
    INVALID_CREDENTIALS = (401, "INVALID_CREDENTIALS", "用户名或密码错误")

    # 枚举相关错误 (2000-2999)
    ENUM_TYPE_EXISTS = (409, "ENUM_TYPE_EXISTS", "枚举类型已存在")
    ENUM_VALUE_EXISTS = (409, "ENUM_VALUE_EXISTS", "枚举值已存在")
    ENUM_ITEM_NOT_FOUND = (404, "ENUM_ITEM_NOT_FOUND", "枚举条目不存在或已删除")

    # 文件相关错误 (3000-3999)
    FILE_NOT_FOUND = (404, "FILE_NOT_FOUND", "文件不存在或已被删除")
    FILE_PHYSICALLY_MISSING = (410, "FILE_PHYSICALLY_MISSING", "文件物理丢失")
    FILE_TYPE_NOT_SUPPORTED = (400, "FILE_TYPE_NOT_SUPPORTED", "不支持的文件类型")
    FILE_SIZE_EXCEEDED = (400, "FILE_SIZE_EXCEEDED", "文件大小超出限制")
    FILE_UPLOAD_FAILED = (500, "FILE_UPLOAD_FAILED", "文件上传失败")
    FILE_ACCESS_DENIED = (403, "FILE_ACCESS_DENIED", "没有文件访问权限")

    # 消息推送相关错误 (4000-4999)
    NOTIFICATION_NOT_FOUND = (404, "NOTIFICATION_NOT_FOUND", "消息不存在或无权限")
    NOTIFICATION_TEMPLATE_NOT_FOUND = (404, "NOTIFICATION_TEMPLATE_NOT_FOUND", "消息模板不存在")

    # 区域相关错误 (4500-4599)
    PROVINCE_NOT_FOUND = (404, "PROVINCE_NOT_FOUND", "省份不存在")
    CITY_NOT_FOUND = (404, "CITY_NOT_FOUND", "城市不存在")
    AREA_NOT_FOUND = (404, "AREA_NOT_FOUND", "区县不存在")
    REGION_CODE_INVALID = (400, "REGION_CODE_INVALID", "区域编码格式无效")

    # 系统错误 (5000-5999)
    INTERNAL_SERVER_ERROR = (500, "INTERNAL_SERVER_ERROR", "内部服务器错误")
    DATABASE_ERROR = (500, "DATABASE_ERROR", "数据库错误")
    DB_QUERY_ERROR = (500, "DB_QUERY_ERROR", "数据库查询错误")
    EXTERNAL_SERVICE_ERROR = (502, "EXTERNAL_SERVICE_ERROR", "外部服务错误")

    @property
    def http_code(self) -> int:
        """HTTP状态码"""
        return self.value[0]

    @property
    def biz_code(self) -> str:
        """业务错误码"""
        return self.value[1]

    @property
    def message(self) -> str:
        """错误描述"""
        return self.value[2]


class BizException(HTTPException):
    """
    业务异常类
    统一使用 ErrorCode 枚举来定义异常信息
    """

    def __init__(
            self,
            error_code: ErrorCode,
            message: Optional[str] = None,
            details: Optional[dict] = None,
            headers: Optional[dict] = None
    ):
        """
        初始化业务异常

        Args:
            error_code: 错误编码（ErrorCode枚举）
            message: 自定义错误消息，为空时使用error_code的默认消息
            details: 额外的错误详情
            headers: HTTP响应头
        """
        self.error_code = error_code
        self.biz_code = error_code.biz_code
        self.error_message = message or error_code.message
        self.error_details = details

        # 构建错误详情
        error_detail = {
            "error_code": error_code.biz_code,
            "message": self.error_message
        }

        if details:
            error_detail["details"] = details

        super().__init__(
            status_code=error_code.http_code,
            detail=error_detail,
            headers=headers
        )

    @property
    def message(self) -> str:
        """获取错误消息"""
        return self.error_message

    @property
    def details(self) -> Optional[dict]:
        """获取错误详情"""
        return self.error_details

    @classmethod
    def from_error_code(cls, error_code: ErrorCode, **kwargs) -> "BizException":
        """
        从错误编码创建异常实例的便捷方法

        Args:
            error_code: 错误编码
            **kwargs: 其他参数

        Returns:
            BizException: 异常实例
        """
        return cls(error_code, **kwargs)

    @classmethod
    def user_not_found(cls, username: str = None) -> "BizException":
        """用户不存在异常"""
        details = {"username": username} if username else None
        return cls(ErrorCode.USER_NOT_FOUND, details=details)

    @classmethod
    def enum_type_exists(cls, type_name: str) -> "BizException":
        """枚举类型已存在异常"""
        return cls(
            ErrorCode.ENUM_TYPE_EXISTS,
            message=f"枚举类型 '{type_name}' 已存在",
            details={"type_name": type_name}
        )

    @classmethod
    def enum_value_exists(cls, type_name: str, value: str) -> "BizException":
        """枚举值已存在异常"""
        return cls(
            ErrorCode.ENUM_VALUE_EXISTS,
            message=f"枚举类型 '{type_name}' 下的值 '{value}' 已存在",
            details={"type_name": type_name, "value": value}
        )

    @classmethod
    def file_not_found(cls, file_id: str = None) -> "BizException":
        """文件不存在异常"""
        details = {"file_id": file_id} if file_id else None
        return cls(ErrorCode.FILE_NOT_FOUND, details=details)
